package com.yhh.college_information_platform.service.impl;

import com.yhh.college_information_platform.common.ResultCode;
import com.yhh.college_information_platform.entity.Resource;
import com.yhh.college_information_platform.exception.BusinessException;
import com.yhh.college_information_platform.mapper.ResourceMapper;
import com.yhh.college_information_platform.service.FilePreviewService;
import com.yhh.college_information_platform.utils.MinioProperties;
import com.yhh.college_information_platform.utils.MinioUtil;
import com.yhh.college_information_platform.vo.FileContentVO;
import com.yhh.college_information_platform.vo.FilePreviewVO;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 文件预览Service实现类
 *
 * @author yhh
 * @date 2025-10-29
 */
@Slf4j
@Service
public class FilePreviewServiceImpl implements FilePreviewService {

    @Autowired
    private ResourceMapper resourceMapper;

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioProperties minioProperties;

    /**
     * 预签名URL默认有效期（秒）
     */
    private static final int DEFAULT_EXPIRY = 3600; // 1小时

    /**
     * 支持预览的文件类型映射
     */
    private static final Map<String, String> PREVIEW_TYPE_MAP = new HashMap<>();

    static {
        // PDF文件
        PREVIEW_TYPE_MAP.put("pdf", "pdf");
        
        // Office文档
        PREVIEW_TYPE_MAP.put("doc", "docx");
        PREVIEW_TYPE_MAP.put("docx", "docx");
        PREVIEW_TYPE_MAP.put("xls", "xlsx");
        PREVIEW_TYPE_MAP.put("xlsx", "xlsx");
        // PPT文件不支持在线预览（需要公网URL才能使用Office Web Viewer）
        // PREVIEW_TYPE_MAP.put("ppt", "pptx");
        // PREVIEW_TYPE_MAP.put("pptx", "pptx");
        
        // 文本文件
        PREVIEW_TYPE_MAP.put("txt", "txt");
        PREVIEW_TYPE_MAP.put("md", "txt");
        PREVIEW_TYPE_MAP.put("log", "txt");
        PREVIEW_TYPE_MAP.put("java", "txt");
        PREVIEW_TYPE_MAP.put("js", "txt");
        PREVIEW_TYPE_MAP.put("json", "txt");
        PREVIEW_TYPE_MAP.put("xml", "txt");
        PREVIEW_TYPE_MAP.put("yml", "txt");
        PREVIEW_TYPE_MAP.put("yaml", "txt");
        PREVIEW_TYPE_MAP.put("properties", "txt");
        
        // 图片文件
        PREVIEW_TYPE_MAP.put("jpg", "image");
        PREVIEW_TYPE_MAP.put("jpeg", "image");
        PREVIEW_TYPE_MAP.put("png", "image");
        PREVIEW_TYPE_MAP.put("gif", "image");
        PREVIEW_TYPE_MAP.put("bmp", "image");
        PREVIEW_TYPE_MAP.put("webp", "image");
        PREVIEW_TYPE_MAP.put("svg", "image");
    }

    @Override
    public FilePreviewVO getPreviewInfo(Long resourceId, Long userId) {
        log.info("获取文件预览信息，资料ID: {}, 用户ID: {}", resourceId, userId);

        // 1. 查询资料信息
        Resource resource = resourceMapper.selectById(resourceId);
        if (resource == null) {
            throw new BusinessException(ResultCode.NOT_FOUND, "资料不存在");
        }

        // 2. 检查资料状态（只有审核通过的资料才能预览）
        if (resource.getStatus() != 1) {
            throw new BusinessException(ResultCode.FORBIDDEN, "该资料未通过审核，暂不支持预览");
        }

        // 3. 从fileUrl中提取bucket和文件名
        String fileUrl = resource.getFileUrl();
        String path = fileUrl.replace(minioProperties.getFileHost() + "/", "");
        String[] parts = path.split("/", 2);
        if (parts.length != 2) {
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "文件路径格式错误");
        }
        String bucketName = parts[0];
        String objectName = parts[1];

        // 4. 获取文件类型和预览类型
        String fileType = resource.getFileType().toLowerCase();
        String previewType = getPreviewType(fileType);
        boolean supported = isSupportPreview(fileType);

        // 5. 生成预签名URL
        String presignedUrl = null;
        if (supported) {
            try {
                presignedUrl = minioUtil.getPresignedObjectUrl(bucketName, objectName, DEFAULT_EXPIRY);
            } catch (Exception e) {
                log.error("生成预签名URL失败", e);
                throw new BusinessException(ResultCode.SYSTEM_ERROR, "生成预览链接失败");
            }
        }

        // 6. 封装返回结果
        FilePreviewVO vo = new FilePreviewVO();
        vo.setResourceId(resourceId);
        vo.setFileName(resource.getFileName());
        vo.setFileType(fileType);
        vo.setFileSize(resource.getFileSize());
        vo.setFileUrl(presignedUrl);
        vo.setPreviewType(previewType);
        vo.setSupported(supported);
        vo.setExpiresIn(DEFAULT_EXPIRY);
        
        if (supported) {
            vo.setMessage("支持在线预览");
        } else {
            vo.setMessage("该文件格式不支持在线预览，请下载后查看");
        }

        log.info("文件预览信息获取成功，预览类型: {}, 是否支持: {}", previewType, supported);
        return vo;
    }

    @Override
    public FileContentVO getTextFileContent(Long resourceId, Long userId) {
        log.info("获取文本文件内容，资料ID: {}, 用户ID: {}", resourceId, userId);

        // 1. 查询资料信息
        Resource resource = resourceMapper.selectById(resourceId);
        if (resource == null) {
            throw new BusinessException(ResultCode.NOT_FOUND, "资料不存在");
        }

        // 2. 检查资料状态
        if (resource.getStatus() != 1) {
            throw new BusinessException(ResultCode.FORBIDDEN, "该资料未通过审核");
        }

        // 3. 检查是否为文本文件
        String fileType = resource.getFileType().toLowerCase();
        String previewType = getPreviewType(fileType);
        if (!"txt".equals(previewType)) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "该文件不是文本文件");
        }

        // 4. 从MinIO读取文件内容
        String fileUrl = resource.getFileUrl();
        String path = fileUrl.replace(minioProperties.getFileHost() + "/", "");
        String[] parts = path.split("/", 2);
        if (parts.length != 2) {
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "文件路径格式错误");
        }
        String bucketName = parts[0];
        String objectName = parts[1];

        try {
            // 读取文件内容
            InputStream stream = minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build()
            );

            // 读取为字符串（限制文件大小，避免内存溢出）
            long fileSize = resource.getFileSize();
            if (fileSize > 10 * 1024 * 1024) { // 限制10MB
                throw new BusinessException(ResultCode.PARAM_ERROR, "文件过大，不支持预览（最大10MB）");
            }

            StringBuilder content = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    content.append(line).append("\n");
                }
            }

            // 5. 封装返回结果
            FileContentVO vo = new FileContentVO();
            vo.setContent(content.toString());
            vo.setEncoding("UTF-8");
            vo.setFileSize(fileSize);
            vo.setFileName(resource.getFileName());
            vo.setFileType(fileType);

            log.info("文本文件内容获取成功，文件大小: {} bytes", fileSize);
            return vo;

        } catch (Exception e) {
            log.error("读取文件内容失败", e);
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "读取文件内容失败");
        }
    }

    @Override
    public boolean isSupportPreview(String fileType) {
        if (fileType == null || fileType.trim().isEmpty()) {
            return false;
        }
        return PREVIEW_TYPE_MAP.containsKey(fileType.toLowerCase());
    }

    @Override
    public String getPreviewType(String fileType) {
        if (fileType == null || fileType.trim().isEmpty()) {
            return "unsupported";
        }
        return PREVIEW_TYPE_MAP.getOrDefault(fileType.toLowerCase(), "unsupported");
    }
}

